/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.netthreads.android.opengl;

import java.io.InputStream;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.microedition.khronos.opengles.GL10;

/**
 * {@hide}
 */
public class Texture
{

    private int width, height, bpp;
    private ByteBuffer data;
    private int name = -1;

    // Texture maps have the following format. All integers
    // are 16 bits, high byte first. Pixels are in 5/6/5
    // RGB format, low byte first.
    //
    // width
    // height
    // pixel (0, 0)
    // pixel (1, 0)
    // ...
    // pixel (width - 1, height - 1)

    private int readInt16(InputStream is) throws IOException
    {
        return is.read() | (is.read() << 8);
    }

    public Texture(InputStream is) throws IOException
    {
        this.width = readInt16(is);
        this.height = readInt16(is);
        this.bpp = 2;

        int npixels = width * height;
        int nbytes = npixels * bpp;
        byte[] arr = new byte[nbytes];

        int idx = 0;
        while (idx < nbytes)
        {
            int nread = is.read(arr, idx, nbytes - idx);
            idx += nread;
        }

        if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN)
        {
            // Swap pairs of bytes on big-endian platforms
            for (int i = 0; i < npixels; i++)
            {
                int j = i * 2;
                int k = j + 1;

                byte tmp = arr[j];
                arr[j] = arr[k];
                arr[k] = tmp;
            }
        }

        this.data = ByteBuffer.allocateDirect(arr.length);
        this.data.order(ByteOrder.nativeOrder());
        data.put(arr);
        data.position(0);
    }

    private int loadTexture(GL10 gl, int textureUnit, int minFilter, int magFilter, int wrapS, int wrapT, int mode, int width, int height, int dataType, Buffer data)
    {
        int[] texture = new int[1];
        gl.glGenTextures(1, texture, 0);

        gl.glEnable(GL10.GL_TEXTURE_2D);
        gl.glClientActiveTexture(textureUnit);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, minFilter);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, magFilter);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, wrapS);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, wrapT);
        gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, mode);

        gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGB, width, height, 0, GL10.GL_RGB, dataType, data);

        return texture[0];
    }

    public void setTextureParameters(GL10 gl)
    {
        if (name < 0)
        {
            name = loadTexture(gl, GL10.GL_TEXTURE0, GL10.GL_NEAREST, GL10.GL_NEAREST, GL10.GL_REPEAT, GL10.GL_REPEAT, GL10.GL_MODULATE, width, height, GL10.GL_UNSIGNED_SHORT_5_6_5, data);
        }

        gl.glBindTexture(GL10.GL_TEXTURE_2D, name);
    }
}
